package com.fjec.activity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fjec.activity.entity.BizGiveGift;
import com.fjec.activity.entity.BizGiveGiftDetail;
import com.fjec.activity.entity.BizUserGift;
import com.fjec.activity.entity.BizUserGiftChangeRecord;
import com.fjec.activity.feign.MarketClient;
import com.fjec.activity.mapper.BizGiveGiftMapper;
import com.fjec.activity.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjec.activity.view.UserGiftVO;
import com.fjec.common.exception.BizException;
import com.fjec.common.shiro.AccountInfo;
import com.fjec.common.util.DateUtil;
import com.fjec.common.util.SpecialMapUtil;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Array;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 002.赠送礼物表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-09-18
 */
@Service
public class BizGiveGiftServiceImpl extends ServiceImpl<BizGiveGiftMapper, BizGiveGift> implements IBizGiveGiftService {

    @Resource
    private BizGiveGiftMapper mapper;

    @Resource
    private IBizGiveGiftDetailService bizGiveGiftDetailService;

    @Resource
    private IBizUserGiftService bizUserGiftService;

    @Resource
    private IBizUserGiftChangeRecordService bizUserGiftChangeRecordService;

    @Resource
    private IRPCService rpcService;

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public int saveGivingGift(Long receId, String shopName, List<UserGiftVO> gifts, String content) {
        // 首先校验用户当前拥有的礼物是否充足
        Long giveId = AccountInfo.getUserId();
        List<BizUserGift> userGifts = bizUserGiftService.list(new QueryWrapper<BizUserGift>()
                .eq("UserId", giveId));

        for (UserGiftVO userGiftVO : gifts) {
            if (userGiftVO.getRequireNum() == null || userGiftVO.getRequireNum() == 0)
                continue;
            Long giftId = userGiftVO.getGiftId();
            Optional<BizUserGift> optionalBizUserGift = userGifts.stream()
                    .filter(ug -> ug.getGiftId().equals(giftId))
                    .findFirst();
            if (optionalBizUserGift.isPresent()) {
                // 用户拥有该礼物，则比较数量
                BizUserGift ug = optionalBizUserGift.get();
                if (ug.getGiftNum() < userGiftVO.getRequireNum())
                    return -1;
                // 更新该礼物剩余数量
                // 更新用户礼物表
                int remaining = ug.getGiftNum() - userGiftVO.getRequireNum();
                ug.setGiftNum(remaining);
                ug.setUpdateTime(DateUtil.nowLdt());
                bizUserGiftService.updateById(ug);
            } else {
                // 用户无此礼物，直接返回failure
                return -1;
            }
        }

        // 礼物赠送记录
        Integer busiType = AccountInfo.getBusiType();
        BizGiveGift giving = new BizGiveGift();
        giving.setGiveId(giveId);
        giving.setBusiType(busiType);
        giving.setReceId(receId);
        giving.setShopName(shopName);
        giving.setContent(content);
        giving.setReceived(0);
        giving.setCreateTime(DateUtil.nowLdt());
        this.save(giving);

        List<BizGiveGiftDetail> giveGiftDetails = new ArrayList<>();
        List<BizUserGiftChangeRecord> changeRecords = new ArrayList<>();

        for (UserGiftVO gift : gifts) {
            if (gift.getRequireNum() == null || gift.getRequireNum() == 0)
                continue;
            // 赠送详情
            BizGiveGiftDetail detail = new BizGiveGiftDetail();
            detail.setGivingId(giving.getId());
            detail.setGiftId(gift.getGiftId());
            detail.setGiftName(gift.getGiftName());
            detail.setGiftNum(gift.getRequireNum());
            detail.setGiftPrice(gift.getAmount());
            detail.setCreateTime(DateUtil.nowLdt());
            int numToBuy = gift.getRequireNum() - gift.getGiftNum();
            detail.setBuyNum(Math.max(numToBuy, 0));
            giveGiftDetails.add(detail);
            // 用户礼物变动记录
            BizUserGiftChangeRecord record = new BizUserGiftChangeRecord();
            record.setUserGiftId(gift.getId());
            record.setOpeType(2);
            record.setNum(-gift.getRequireNum());
            record.setBusiData(String.valueOf(giving.getId()));
            record.setCreateTime(DateUtil.nowLdt());
            changeRecords.add(record);
        }

        bizGiveGiftDetailService.saveBatch(giveGiftDetails);
        bizUserGiftChangeRecordService.saveBatch(changeRecords);
        return 0;
    }

    @Override
    public List<Map<String, Object>> getMyGivingRecords(Long userId, Integer busiType) {
        List<BizGiveGift> gives = this.list(new QueryWrapper<BizGiveGift>()
                .eq("GiveId", userId)
                .eq("BusiType", busiType)
                .orderByDesc("CreateTime"));

        List<Long> givingIds = gives.stream().map(BizGiveGift::getId).collect(Collectors.toList());

        if (givingIds.size() == 0)
            return new ArrayList<>();
        List<Map<String, Object>> giftDetails = bizGiveGiftDetailService.listMaps(new QueryWrapper<BizGiveGiftDetail>()
                                                                                    .in("GivingId", givingIds));
        Map<Long, List<Map<String, Object>>> givingId2Details = new HashMap<>();
        List<Map<String, Object>> giftInfos = rpcService.getGiftInfo(3);
        giftDetails.forEach(d -> {
            Long giftId = MapUtils.getLong(d, "GiftId");
            Optional<Map<String, Object>> giftInfo = giftInfos.stream().filter(info -> MapUtils.getLong(info, "Id").equals(giftId)).findFirst();
            if (giftInfo.isPresent()) {
                Map<String, Object> g = giftInfo.get();
                d.put("giftPic", MapUtils.getString(g, "ServPic"));
            }
            Long givingId = MapUtils.getLong(d, "GivingId");
            givingId2Details.computeIfAbsent(givingId, k -> new ArrayList<>());
            givingId2Details.get(givingId).add(SpecialMapUtil.lowKey(d));
        });

        List<Map<String, Object>> result = new ArrayList<>();
        ObjectMapper om = new ObjectMapper();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (BizGiveGift give : gives) {
            String createTime = give.getCreateTime().format(formatter);
            String receiveTime = "";
            if (give.getReceived() == 1)
                receiveTime = give.getUpdateTime().format(formatter);
            Long givingId = give.getId();
            Map<String, Object> giveMap = om.convertValue(give, Map.class);
            List<Map<String, Object>> gifts = givingId2Details.get(givingId);
            giveMap.put("hasBuy", gifts.stream().anyMatch(g -> MapUtils.getInteger(g, "buyNum") > 0));
            giveMap.put("gifts", gifts);
            giveMap.put("createTime", createTime);
            giveMap.put("receiveTime", receiveTime);
            giveMap.remove("updateTime");
            result.add(giveMap);
        }

        return result;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Map<String, Object> receiveGift(Long givingId) {
        Map<String, Object> result = new HashMap<>();
        int totalPrice = 0;
        Long userId = AccountInfo.getUserId();
        // 更新赠送礼物表
        BizGiveGift bizGiveGift = this.getOne(new QueryWrapper<BizGiveGift>().eq("Id", givingId));
        if (bizGiveGift.getReceived() == 1) {
            result.put("receivedGifts", new ArrayList<>());
            result.put("content", "");
            result.put("totalValue", 0);
            return result;
        }
        bizGiveGift.setReceived(1);
        bizGiveGift.setUpdateTime(DateUtil.nowLdt());
        this.updateById(bizGiveGift);
        // 获取本次赠送的礼物信息
        List<BizGiveGiftDetail> giftDetails = bizGiveGiftDetailService.list(
                new QueryWrapper<BizGiveGiftDetail>().eq("GivingId", givingId));
        result.put("receivedGifts", giftDetails);
        result.put("content", bizGiveGift.getContent());
        // 更新被赠送用户礼物表
        List<BizUserGift> bizUserGifts = new ArrayList<>();

        for (BizGiveGiftDetail detail : giftDetails) {
            totalPrice += detail.getGiftPrice() * detail.getGiftNum();

            BizUserGift userGift = bizUserGiftService.getOne(
                    new QueryWrapper<BizUserGift>().eq("UserId", userId).eq("GiftId", detail.getGiftId()));

            if (userGift != null) {
                userGift.setGiftNum(userGift.getGiftNum() + detail.getGiftNum());
                userGift.setUpdateTime(DateUtil.nowLdt());
                bizUserGifts.add(userGift);
            } else {
                userGift = new BizUserGift();
                userGift.setUserId(userId);
                userGift.setGiftId(detail.getGiftId());
                userGift.setGiftNum(detail.getGiftNum());
                userGift.setCreateTime(DateUtil.nowLdt());
                userGift.setUpdateVer(0);
                bizUserGifts.add(userGift);
            }
        }
        bizUserGiftService.saveOrUpdateBatch(bizUserGifts);
        result.put("totalValue", totalPrice);

        // 更新用户礼物变动表
        List<BizUserGiftChangeRecord> records = new ArrayList<>();
        for (int i = 0; i < bizUserGifts.size(); i++) {
            BizUserGift userGift = bizUserGifts.get(i);
            BizUserGiftChangeRecord changeRecord = new BizUserGiftChangeRecord();
            changeRecord.setUserGiftId(userGift.getId());
            changeRecord.setNum(giftDetails.get(i).getGiftNum());
            changeRecord.setOpeType(3);
            changeRecord.setBusiData(String.valueOf(givingId));
            changeRecord.setCreateTime(DateUtil.nowLdt());
            records.add(changeRecord);
        }
        bizUserGiftChangeRecordService.saveBatch(records);

        return result;
    }
}
